package merlin.servlets;

import java.io.*;
import java.util.*;
import java.util.zip.*;
import java.text.*;

import javax.servlet.*;
import javax.servlet.http.*;

import merlin.beans.*;
import merlin.dao.*;
import merlin.managers.*;
import merlin.utils.*;

import org.apache.jasper.runtime.JspRuntimeLibrary;



/**
 * Front contoller for the Merlin Scott web application.
 */
public class MerlinServlet extends HttpServlet{

	int maxRecords ;	// maximum number of records to be fetched

	Thread reportRefresher ;	// Thread to refresh the report titles.

	boolean titlesLoaded = false;	//one-time operation.

	// User types
	static final Integer USER_TYPE_MERLIN_RESEARCHER = new Integer(1);
	static final Integer USER_TYPE_FREE_UPDATES = new Integer(2);
	//static final Integer USER_TYPE_EXISTING_CUSTOMER = new Integer(3);
	//static final Integer USER_TYPE_NEW_CUSTOMER = new Integer(4);

	/**
	 * @param cfg	servlet config.
	 */
	public void init(ServletConfig cfg)throws ServletException{
		try{
			super.init(cfg);

			ApplicationResources resource = ApplicationResources.getInstance();
			try{
				String str = resource.getProperty("search.maxselect");
	        	if(str != null)maxRecords = Integer.parseInt(str);
			}catch(Exception e){
				e.printStackTrace();
			}

			// Launch the report titles refresher thread.
			int refreshInterval = 24;	// default every 24 hours.
			try{
				String str = resource.getProperty("report.refresh.interval");
	        	if(str != null)refreshInterval = Integer.parseInt(str);
			}catch(Exception e){
				System.out.println(e);
			}
			reportRefresher = new ReportRefresher(cfg.getServletContext(),refreshInterval);
			reportRefresher.start();

			// Put a Set in the servlet context that holds the currently logged-in usernames.
			// Usernames will be added whenever there is a successful login and removed when the
			// user's session times out or is explicity logged out. This is used the prevent multiple
			// users logging in with the same user-id simlutaneously.
			// The addition is done in the loginXXX() functions and removal is doen from the
			// ServerManagement classes' code , which gets activated whenever a session invalidation happens.
			//cfg.getServletContext().setAttribute("setLoggedInUsers",new HashSet());
			cfg.getServletContext().setAttribute("mapLoggedInUsers",new HashMap());

			System.out.println("servlet inited");
		}catch(Exception e){
			e.printStackTrace();
			throw new UnavailableException("Problem in loading MerlinServlet"); // servlet is not usable.
		}
	}

	/**
	 *
	 */
	public void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
		doPost(request,response);
	}

	/**
	 *
	 */
	public void doPost(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{

		try{

			// verify whether the database server is available or not by checking the existence of the
			// specified file. If the file exists then the database is currently unavailable.
			String fileName = ApplicationResources.getInstance().getProperty("fileNameToCheckDBAvailibility");

			if(fileName != null){
				File file =  new File(fileName);
				//System.out.println("file " + file + " exists : " + file.exists());
				// system is unavailable.
				if(file.exists()){
					request.setAttribute("pageName","mr_serviceUnavailable.jsp");
					dispatch(request,response,"/mr_kickout.jsp",false);
					return;
				}
			}


			String mode = request.getParameter("mode");

			// trace logger
			System.out.println(">>>>>>>>>>>>>>>>");
			System.out.println(new java.util.Date().toLocaleString() + " mode : " + mode);

			if(mode==null || mode.equals("")){
				dispatch(request,response,"mr_login.jsp",true);
				return;
			};

			// called before sanity check because it is required to load the titles list.
			if(mode.equals("loadTitles")){
				handleLoadTitles(request,response);
				return;
			}


			if(mode.equals("login")){
				handleLogin(request,response);
				return;
			}

            if(mode.equals("loginForFreeUpdates")){
				handleLoginForFreeUpdates(request,response);
				return;
			}

            if(mode.equals("register")){
				dispatch(request,response,"/mr_registration.jsp",false);
				return;
			}

			if(mode.equals("searchReportsByReportDesc")){
				handleSearchReportsByDesc(request,response);
				return;
			}

			if(mode.equals("saveNewEnquiry")){
				handleSaveNewEnquiry(request,response);
				return;
			}

			if(mode.equals("saveNewPaymentDetails")){
				handleSaveNewPaymentDetails(request,response);
				return;
			}

			if(mode.equals("saveNewCustomerRegistration")){
				handleSaveNewCustomerRegistration(request,response);
				return;
			}

			if(mode.equals("saveNewIWOrder")){
				handleSaveNewIWOrder(request,response);
				return;
			}

			if(mode.equals("IWReRegistration")){
				handleIWReRegistration(request,response);
				return;
			}

			if(mode.equals("3DSecureCallback")){
				handle3DSecureCallback(request,response);
				return;
			}

			if(mode.equals("checkForLoginExistance")){
				handleCheckForLoginExistance(request,response);
				return;
			}

			if(mode.equals("buyPdfCredits")){
				handleBuyPdfCredits(request,response);
				return;
			}

			if(mode.equals("generateReportDownload")){
				handleGenerateReportDownload(request,response);
				return;
			}

			if(mode.equals("pdfReportDownload")){
            	handlePdfReportDownload(request,response);
            	return;
			}

			if(mode.equals("loginForControlSystem")){
				handleLoginForControlSystem(request,response);
				return;
			}

			if(mode.equals("downloadMailingList")){
				handleDownloadMailingList(request,response);
				return;
			}

			if(mode.equals("printerLabelGeneration")){
				handlePrinterLabelGeneration(request,response);
				return;
			}

			if(mode.equals("msalFreeReportDownload")){
				handleMSALFreeReportDownload(request, response);
			    return;
			}
			
			//~~ All the commands after this session check require that the user has logged in first.
			// Sanity check
			if((request.getSession() == null || request.getSession().getAttribute("username")==null) && ! mode.equals("login")){
				request.setAttribute("pageName",ApplicationResources.getInstance().getProperty("homepage.url"));
				dispatch(request,response,"/mr_kickout.jsp",false);
				return;
			}

			if(mode.equals("logout")){
				handleLogout(request,response);
				return;
			}

			if(mode.equals("mainFrame")){
				dispatch(request,response,"/mr_mainframe.jsp",false);
				return;
			}

			if(mode.equals("searchCompanyByKeyword")){
				handleSearchCompaniesByKeyword(request,response);
				return;
			}
			if(mode.equals("searchCompanyByCompanyNumber")){
				handleSearchCompanyByCompanyNumber(request,response);
				return;
			}
			if(mode.equals("searchCompanyByDirector")){
				handleSearchCompaniesByDirector(request,response);
				return;
			}
			if(mode.equals("searchCompanyByParent")){
				handleSearchCompaniesByParent(request,response);
				return;
			}
			if(mode.equals("sendMail")){
				handleSendMail(request,response);
				return;
			}
			if(mode.equals("sendMailToAddRemoveCompanies")){
				handleSendMailToAddRemoveCompanies(request,response);
				return;
			}


			if(mode.equals("createPDF")){
				handleCreatePDF(request,response);
				return;
			}

			if(mode.equals("pdfReportDownloadFreeUpdates")){
				handlePdfReportDownloadFreeUpdates(request,response);
			    return;
			}

			// if mode is unknown send to invalid-request message
			dispatch(request,response,"/mr_invalidrequest.jsp",false);

		}catch(Exception e){
			System.out.println("CAUGHT");
			e.printStackTrace();
			request.setAttribute("javax.servlet.jsp.jspException",e); //the exception implicit JSP object.
			dispatch(request,response,"/mr_errhandler.jsp",false);
		}
	}

	/**
	 *
	 */
	public void destroy(){
		System.out.println("Servlet going down");
		this.reportRefresher.interrupt();
	}

	/**
	 * log-in the user and send him to the next view
	 */
	protected void handleLogin(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{

    	// convert the user name to lowercase
		String uid = request.getParameter("txtUserName");
		String pwd = request.getParameter("txtPassword");

		String nextView=null;
		if(uid == null || uid.length() == 0 || pwd == null || pwd.length() == 0){
			// insufficient information.
			request.setAttribute("error.login","Invalid Username/password");
			nextView = "/mr_login.jsp";
		}else{
			uid = uid.toLowerCase().trim();

			String uidAndClientIP = uid + ":" + request.getRemoteAddr();

			//System.out.println(uid + " exists : " + ((Set)getServletContext().getAttribute("setLoggedInUsers")).contains(uid));
			System.out.println(uidAndClientIP + " exists : " + ((Map)getServletContext().getAttribute("mapLoggedInUsers")).containsValue(uidAndClientIP));
			// find out if someone is already logged in with this user-id from some other IP address.
			//if(((Set)getServletContext().getAttribute("setLoggedInUsers")).contains(uid)){
			if(isAnotherUserLoggedInFromAnotherIP(uidAndClientIP,((Map)getServletContext().getAttribute("mapLoggedInUsers")).values().iterator())){
				// some one is already logged in.
				request.setAttribute("error.login","Some other user is already logged in with this Username from a different computer.");
				nextView = "/mr_login.jsp";
			}else{

				MsalResearchersBean bean = MsalResearchersManager.login(uid,pwd);
				if(bean==null){
					// login has failed
					bean = new MsalResearchersBean(uid,pwd,0);
					request.setAttribute("error.login","Invalid Username/password");
					nextView = "/mr_login.jsp";
				}else{
					HttpSession session = request.getSession(true);
					//session.setAttribute("username",bean.getUserName());
					session.setAttribute("username",uid);
		   			session.setAttribute("reportId",request.getParameter("selReport"));
	   				session.setAttribute("reportTitle",request.getParameter("reportTitle"));
	   				session.setAttribute("userType",USER_TYPE_MERLIN_RESEARCHER);

					//((Set)getServletContext().getAttribute("setLoggedInUsers")).add(uid);
					((Map)getServletContext().getAttribute("mapLoggedInUsers")).put(session.getId(),uidAndClientIP);

	   				// fetch the previously selected companies from the database.
	   				ArrayList list = MsalResearchersManager.getSelectedCompanies(bean.getUserName(),Integer.parseInt(request.getParameter("selReport")));
	   				if(list != null && list.size() > 0){
	   					StringBuffer sBufComps = new StringBuffer();
	   					String separatorString = ApplicationResources.getInstance().getProperty("separatorString");
						int length = list.size();
						for(int i=0;i<length - 1;i++){
							String arr[] = (String[])list.get(i);
							sBufComps.append(arr[0]).append(separatorString).append(arr[1]).append(separatorString);
						}
						String arr[] = (String[])list.get(length - 1);
						sBufComps.append(arr[0]).append(separatorString).append(arr[1]);

		   				session.setAttribute("selectedCompanies",sBufComps.toString());
		   			}else{
		   				// remove any pre-existing list in the session.
		   				session.removeAttribute("selectedCompanies");
		   			}
					nextView= "/mr_mainframe.jsp";
				}
			}
		}

		dispatch(request,response,nextView,false);
	}

	/**
	 * log-in the user for the "Free Updates" section
	 */
	protected void handleLoginForFreeUpdates(HttpServletRequest request,HttpServletResponse response)
				throws ServletException,IOException,ParseException{

		String uid = request.getParameter("txtEmailAddress");

		String nextView=null;
		if(uid == null || uid.length() == 0){
			// insufficient information.
			request.setAttribute("error.login","Invalid email ID");
			nextView = "/mr_loginFreeUpdates.jsp";
		}else{
			uid = uid.toLowerCase().trim();

			String uidAndClientIP = uid + ":" + request.getRemoteAddr();

			// find out if someone is already logged in with this user-id.
			//System.out.println("login for " + uid + " " + ((Set)getServletContext().getAttribute("setLoggedInUsers")).contains(uid));
			System.out.println("login for " + uidAndClientIP + " " + ((Map)getServletContext().getAttribute("mapLoggedInUsers")).containsValue(uidAndClientIP));
			//if(((Set)getServletContext().getAttribute("setLoggedInUsers")).contains(uid)){
			if(isAnotherUserLoggedInFromAnotherIP(uidAndClientIP,((Map)getServletContext().getAttribute("mapLoggedInUsers")).values().iterator())){
				// some one is already logged in.
				request.setAttribute("error.login","Some other user is already logged in with this Username from another computer.");
				nextView = "/mr_loginFreeUpdates.jsp";
			}else{

				CustomerDetailsBean bean = MsalResearchersManager.loginForFreeUpdates(uid);
				if(bean==null){
					// login has failed
					request.setAttribute("error.login","Invalid email ID");
					nextView = "/mr_loginFreeUpdates.jsp";
				}else{
					// check for the validity of the user's subscripttion.

	    			// Convert the java.sql.Date into java.util.Date , as the former
	    			// doesn't support hh:mm:ss information, and move the date to the
					// last second possible for the end date. The subscription should
					// be valid till the last hours of the last date.
					Date subsEndDate =  new Date(bean.getSubscriptionEndDate().getTime());
	    			subsEndDate.setHours(23);
	    			subsEndDate.setMinutes(59);
	    			subsEndDate.setSeconds(59);

	    			System.out.println("end date " + subsEndDate);

					long expiryDateMillis 	= subsEndDate.getTime();

					long currentDateMillis 	= System.currentTimeMillis();

					System.out.println("current constructed date " + new Date(currentDateMillis));

					if(currentDateMillis < expiryDateMillis){
						//  subscription is still valid.
						HttpSession session = request.getSession(true);
						//session.setAttribute("username",bean.getEmailAddress());
						session.setAttribute("username",uid);
		   				session.setAttribute("reportId",String.valueOf(bean.getReportTitlesId()));
	   					session.setAttribute("reportTitle",bean.getReportTitle());
	   					session.setAttribute("userType",USER_TYPE_FREE_UPDATES);
	   					// Get the reports for this user.
						String reportIds = String.valueOf(bean.getReportTitlesId());
						if(bean.getAdditionalReportNumbers() != null){
							reportIds += bean.getAdditionalReportNumbers().replace('/',',');
						}

						DbResultSet reportsForUser = ReportTitlesManager.selectReportTitlesRecords("REPORT_TITLES_ID in(" + reportIds + ")"," REPORT_TITLE ASC");
						session.setAttribute("reportsForUser", reportsForUser);

						//((Set)getServletContext().getAttribute("setLoggedInUsers")).add(uid);
						((Map)getServletContext().getAttribute("mapLoggedInUsers")).put(session.getId(),uidAndClientIP);

	   					// check if the subscription is about to expire in the next n days(default n = 30).
	   					int cutoffDays = Integer.parseInt(ApplicationResources.getInstance().getProperty("registration.expiry.days","30"));
						long diff = expiryDateMillis - currentDateMillis;
						int days = (int)(diff/(1000*60*60*24));

						if(days < cutoffDays){
							// prompt the user to re-subscribe to the service before going forward.

							// format the date into a user-friendly format.(default is dd-MMM-yyyy)
			    			String dateFormat = ApplicationResources.getInstance().getProperty("display.dateformat","dd-MMM-yyyy");
			    			SimpleDateFormat df = new SimpleDateFormat(dateFormat);
	    					String strFormattedDate = df.format(subsEndDate);
							request.setAttribute("subsEndDate",strFormattedDate + " (in " + days + " days)");
							session.setAttribute("emailAddress",bean.getEmailAddress()); // used for auto-filling textfield in order-entry form
							// fetch the previously ordered reports
	                        DbResultSet results = reportsForUser;
	                        int size = results.size();
							// create a string in the <report_id>|<report_name>|<report_id>... format
	                        if( size > 0){
		                        StringBuffer reportTitles = new StringBuffer();
		                        String separatorString = ApplicationResources.getInstance().getProperty("separatorString");
		                        for(int i = 0; i< size - 1; i++){
			                        ReportTitlesBean rtBean = (ReportTitlesBean)results.get(i);
			                        reportTitles.append(rtBean.getReportTitlesId()).append(separatorString).append(rtBean.getReportTitle()).append(separatorString);
								}
								ReportTitlesBean rtBean = (ReportTitlesBean)results.get(size - 1);
							    reportTitles.append(rtBean.getReportTitlesId()).append(separatorString).append(rtBean.getReportTitle());

							    request.setAttribute("hidSelectedReports",reportTitles.toString());
							}
							session.setAttribute("userDetails",bean);
							nextView ="/mr_askForReregistration.jsp";
						}else{
							session.setAttribute("userDetails",bean);
							nextView= "/mr_mainframe.jsp";
						}
					}else{
						// subscription has expired.
						request.setAttribute("subscription.expired",Boolean.TRUE);
						HttpSession session = request.getSession(true);
						session.setAttribute("userType",USER_TYPE_FREE_UPDATES);
						session.setAttribute("emailAddress",bean.getEmailAddress()); // used for auto-filling textfield in order-entry form
						// fetch the previously ordered reports
						// in the <report_id>|<report_name>|<report_id>... format
						String whereClause = "REPORT_TITLES_ID IN(" + bean.getReportTitlesId();
						if(bean.getAdditionalReportNumbers() != null){
							//format is  /<reportid>/<reportid>
							whereClause += bean.getAdditionalReportNumbers().replace('/',',');
						}
						whereClause += ")";
	                    DbResultSet results = ReportTitlesManager.selectReportTitlesRecords(whereClause,null);
	                    int size = results.size();
	                    if( size > 0){
	                        StringBuffer reportTitles = new StringBuffer();
	                        String separatorString = ApplicationResources.getInstance().getProperty("separatorString");
	                        for(int i = 0; i< size - 1; i++){
		                        ReportTitlesBean rtBean = (ReportTitlesBean)results.get(i);
		                        reportTitles.append(rtBean.getReportTitlesId()).append(separatorString).append(rtBean.getReportTitle()).append(separatorString);
							}
							ReportTitlesBean rtBean = (ReportTitlesBean)results.get(size - 1);
						    reportTitles.append(rtBean.getReportTitlesId()).append(separatorString).append(rtBean.getReportTitle());

						    request.setAttribute("hidSelectedReports",reportTitles);
						}
						nextView = "/mr_askForReregistration.jsp";
					}
				}
			}
		}
		dispatch(request,response,nextView,false);
	}


	protected void handleLoginForControlSystem(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
		String userName = request.getParameter("txtUserName");
		String password = request.getParameter("txtPassword");

		boolean success = MSALControlSystemManager.loginForControlSystem(userName,password);

		if(success){
			request.getSession().setAttribute("MSALControlUser",userName);
			dispatch(request,response,"mr_msalControlSystemMainPage.jsp",true);
		}else{
			request.setAttribute("error.login","Invalid username/password");
			dispatch(request,response,"/mr_loginControlSystem.jsp",false);
		}
	}


	/**
	 *	Logout
	 */
	protected void handleLogout(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
		String nextView = "/mr_login.jsp";	// where to go from here,varies according to the type of user.

 		HttpSession session = request.getSession(false);
 		if(session != null){
			// determine the type of user.
			Integer iObj = (Integer)session.getAttribute("userType");
			if(USER_TYPE_FREE_UPDATES.equals(iObj)){
				nextView = "/mr_loginFreeUpdates.jsp";
			}else{
				nextView = "/mr_login.jsp";
			}
			session.invalidate();
		}
		dispatch(request,response,nextView,false);
	}

	/**
	 * Company search based on keyword.
	 */
	protected void handleSearchCompaniesByKeyword(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
		String searchString		 = request.getParameter("hidSearch");
		String searchType		 = request.getParameter("hidSearchType");

		String whereClause =null;

		ApplicationResources resource = ApplicationResources.getInstance();

		try{
			if("alphakey".equals(searchType)){
				searchString = MerlinUtilities.cleanStringForAlphakeySearch(searchString);
				if(searchString.length() > 0)whereClause= " ALPHAKEY_COMPANY_NAME LIKE '" + searchString + "%' ";
			}else{
				// Keyword based search - clean the search string
		     	searchString = MerlinUtilities.parseSearchString(searchString,"&");
				if(searchString.length() > 0)whereClause= " SATISFIES(NSD.IDX_COMPANY_DATA,'" + searchString + "') ";
	    	}

			// the order by clause
			String orderBy = "COMPANY_NAME";

			DbResultSet result  = LookupDetailsManager.selectTopLookupDetailsByKeywordRecords(whereClause,orderBy,maxRecords) ;
			// put the result into the request
			request.setAttribute("result",result);

			if(result.size() > 0 ){
				// if some records were found, retrieve the details of the first record.
				LookupDetailsBean ldBean = (LookupDetailsBean)result.get(0);
				String companyId = ldBean.getCompanyNumber();
				ldBean = LookupDetailsManager.selectLookupDetailsByPK(companyId);
				request.setAttribute("companyDetails",ldBean);
	   			DbResultSet dbRes = ShareholderDetailsManager.selectShareholderDetailsRecordsByCompanyNumber(companyId);
	   			request.setAttribute("shareholderDetails",dbRes);
				dbRes = DirectorDetailsManager.selectDirectorDetailsRecordsByCompanyNumber(companyId);
				request.setAttribute("directorDetails",dbRes);
				dbRes = ParentSubsidiaryDetailsManager.selectParentSubsidiaryDetailsRecordsByCompanyNumber(companyId);
				request.setAttribute("parentSubsidiaryDetails",dbRes);
				dbRes = FinancialDetailsManager.selectFinancialDetailsRecordsByCompanyNumber(companyId);
				request.setAttribute("financialDetails",dbRes);
			}

			String nextView = "/mr_searchCompaniesByKeyword.jsp";
			dispatch(request,response,nextView,false);
    	}catch(RuntimeException re){
    		System.out.println("Caught : " + re);
			request.setAttribute("javax.servlet.jsp.jspException",re); //the exception implicit JSP object.
			dispatch(request,response,"/mr_searchError.jsp",false);
    	}
	}

	/**
	 *
	 */
	protected void handleSearchCompanyByCompanyNumber(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
		String searchString		 = request.getParameter("hidSearch");

        ApplicationResources resource = ApplicationResources.getInstance();

		LookupDetailsBean ldBean  = LookupDetailsManager.selectLookupDetailsByPK(searchString) ;
		// put the result into the request
		request.setAttribute("companyDetails",ldBean);

		if(ldBean != null){
			// if some record was found, retrieve the details of the record.
			String companyId = ldBean.getCompanyNumber();
   			DbResultSet dbRes = ShareholderDetailsManager.selectShareholderDetailsRecordsByCompanyNumber(companyId);
   			request.setAttribute("shareholderDetails",dbRes);
			dbRes = DirectorDetailsManager.selectDirectorDetailsRecordsByCompanyNumber(companyId);
			request.setAttribute("directorDetails",dbRes);
			dbRes = ParentSubsidiaryDetailsManager.selectParentSubsidiaryDetailsRecordsByCompanyNumber(companyId);
			request.setAttribute("parentSubsidiaryDetails",dbRes);
			dbRes = FinancialDetailsManager.selectFinancialDetailsRecordsByCompanyNumber(companyId);
			request.setAttribute("financialDetails",dbRes);
		}

		String nextView = "/mr_searchCompanyByCompanyNumber.jsp";
		dispatch(request,response,nextView,false);
	}

	/**
	 *
	 */
	protected void handleSearchCompaniesByDirector(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
		String searchString		 = request.getParameter("hidSearch");

        ApplicationResources resource = ApplicationResources.getInstance();

		DbResultSet result  = LookupDetailsManager.selectLookupDetailsRecordsByDirector(searchString);
		// put the result into the request
		request.setAttribute("result",result);

		if(result.size() > 0 ){
			// if some records were found, retrieve the details of the first record.
			LookupDetailsBean ldBean = (LookupDetailsBean)result.get(0);
			String companyId = ldBean.getCompanyNumber();
			ldBean = LookupDetailsManager.selectLookupDetailsByPK(companyId);
			request.setAttribute("companyDetails",ldBean);
   			DbResultSet dbRes = ShareholderDetailsManager.selectShareholderDetailsRecordsByCompanyNumber(companyId);
   			request.setAttribute("shareholderDetails",dbRes);
			dbRes = DirectorDetailsManager.selectDirectorDetailsRecordsByCompanyNumber(companyId);
			request.setAttribute("directorDetails",dbRes);
			dbRes = ParentSubsidiaryDetailsManager.selectParentSubsidiaryDetailsRecordsByCompanyNumber(companyId);
			request.setAttribute("parentSubsidiaryDetails",dbRes);
			dbRes = FinancialDetailsManager.selectFinancialDetailsRecordsByCompanyNumber(companyId);
			request.setAttribute("financialDetails",dbRes);
		}

		String nextView = "/mr_searchCompaniesByKeyword.jsp";
		dispatch(request,response,nextView,false);
	}

	/**
	 *
	 */
    protected void handleSearchCompaniesByParent(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
		String searchString	= request.getParameter("hidSearch");

		ApplicationResources resource = ApplicationResources.getInstance();

		LookupDetailsBean ldBean  = LookupDetailsManager.selectLookupDetailsByPK(searchString) ;
		// simulate the finding of multiple records
		DbResultSet result = new DbResultSet();
		result.add(ldBean);
		// put the result into the request
		request.setAttribute("result",result);

		if(ldBean != null){
			// if some record was found, retrieve the details of the record.
			String companyId = ldBean.getCompanyNumber();

   			DbResultSet dbRes = ShareholderDetailsManager.selectShareholderDetailsRecordsByCompanyNumber(companyId);
   			request.setAttribute("shareholderDetails",dbRes);
			dbRes = DirectorDetailsManager.selectDirectorDetailsRecordsByCompanyNumber(companyId);
			request.setAttribute("directorDetails",dbRes);
			dbRes = ParentSubsidiaryDetailsManager.selectParentSubsidiaryDetailsRecordsByCompanyNumber(companyId);
			request.setAttribute("parentSubsidiaryDetails",dbRes);
			dbRes = FinancialDetailsManager.selectFinancialDetailsRecordsByCompanyNumber(companyId);
			request.setAttribute("financialDetails",dbRes);
		}

		String nextView = "/mr_searchCompaniesByParent.jsp";

		dispatch(request,response,nextView,false);
	}

    /**
     *
     */
	protected void handleSendMail(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
		String message  = request.getParameter("hidCompanies");

		HttpSession session = request.getSession(false);
		String mailFrom     = (String)session.getAttribute("username");
		String reportId     = (String)session.getAttribute("reportId");
		String reportTitle  = (String)session.getAttribute("reportTitle");

        String arrCompanies[] = null;

        ApplicationResources resource = ApplicationResources.getInstance();

		/////////////////////////////////////////////////////
		if(message != null && message.length() > 0){
			// capture only the company ids.
			String separatorPattern = resource.getProperty("separatorPattern");
			arrCompanies = message.split(separatorPattern);
			//int arrReportIds[] = new int[arrRawReports.length/2];
			StringBuffer strCompaniesToSave = new StringBuffer();
			for(int i=0;i<arrCompanies.length;i+=2){
				strCompaniesToSave.append('\'').append(arrCompanies[i]).append('\'').append(',');
			}
			// remove the last "," character
			strCompaniesToSave.deleteCharAt(strCompaniesToSave.length() - 1);
		}
		/////////////////////////////////////////////////////
		StringBuffer sbMessage 	  = new StringBuffer();
		StringBuffer sbAttachment = new StringBuffer();

  		sbMessage.append("<font face=\'verdana\'>");
		sbMessage.append("E-Mail Address : ").append(mailFrom).append("<BR>");
		sbMessage.append("<HR>");
		sbMessage.append("<BR><FONT COLOR=\'BLUE\'>Report ID : ").append(reportId).append("<BR>");
		sbMessage.append("<B>Report Title : ").append(reportTitle).append("</FONT></B><P>");
		sbMessage.append("<HR>");
		if(arrCompanies!= null){
  		for(int i=0;i<arrCompanies.length;i+=2){
  			String companyNumber = arrCompanies[i];
  			sbMessage.append("<BR><font color=\'green'>Company Number : ").append(companyNumber).append("</font>");	// Company number.
  			sbMessage.append("<BR><B><font color=\'#95B3DE'>Company Name   : ").append(arrCompanies[i + 1]).append("</font></B>");	// Company name.
  			sbMessage.append("<BR>");

  			sbAttachment.append(companyNumber).append(',').append(reportId).append("\r\n");
	  		}
  		}
  		sbMessage.append("</font>");
  		sbMessage.append("<P><PRE>").append(sbAttachment).append("</PRE>");


		String mailTo  = resource.getProperty("mail.to");

		String subject = null;	// subject of the mail varies according to the type of user.
		String nextView = null;	// where to go from here,varies according to the type of user.

		// determine the type of user.
		Integer iObj = (Integer)session.getAttribute("userType");
		if(USER_TYPE_FREE_UPDATES.equals(iObj)){
			subject = resource.getProperty("mail.subject.freeupdates");
			nextView = "/mr_loginFreeUpdates.jsp";
		}else{
			subject = resource.getProperty("mail.subject.merlinreseacher");
			nextView = "/mr_login.jsp";
		}

		MailSender.sendMail(mailFrom,mailTo,subject,sbMessage.toString());
		request.setAttribute("message","Mail sent successfully");

		// clean the servletcontext data explicitly
		/*
		String username = (String)session.getAttribute("username");
		boolean status =  ((Set)getServletContext().getAttribute("setLoggedInUsers")).remove(username);
  		System.out.println("in sendmail removed " + username + " : " + status);
  		*/
		session.invalidate();

		dispatch(request,response,nextView,false);
	}

	protected void handleSendMailToAddRemoveCompanies(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
		String message  = request.getParameter("hidCompanies");
		String removeMessage =  request.getParameter("hidCompaniesToRemove");

		HttpSession session = request.getSession(false);
		String mailFrom     = (String)session.getAttribute("username");
		String reportId     = (String)session.getAttribute("reportId");
		String reportTitle  = (String)session.getAttribute("reportTitle");

        String arrCompanies[] = null, arrCompaniesToRemove[] = null;

        ApplicationResources resource = ApplicationResources.getInstance();
        String separatorPattern = resource.getProperty("separatorPattern");

		/////////////////////////////////////////////////////
		if(message != null && message.length() > 0){
			arrCompanies = message.split(separatorPattern);
		}

		if(removeMessage != null && removeMessage.length() > 0){
			arrCompaniesToRemove = removeMessage.split(separatorPattern);
		}

		/////////////////////////////////////////////////////
		StringBuffer sbMessage 	  = new StringBuffer();
		StringBuffer sbAttachment = new StringBuffer();

  		sbMessage.append("<font face=\'verdana\'>");
		sbMessage.append("E-Mail Address : ").append(mailFrom).append("<BR>");
		sbMessage.append("<HR>");
		sbMessage.append("<BR><FONT COLOR=\'BLUE\'>Report ID : ").append(reportId).append("<BR>");
		sbMessage.append("<B>Report Title : ").append(reportTitle).append("</FONT></B><P>");

		// Companies to add

		if(arrCompanies!= null){
			sbMessage.append("<font color=\'green'>");
			sbMessage.append("<HR><B>Companies to Add</B><HR>");
  			for(int i=0;i<arrCompanies.length;i+=2){
	  			String companyNumber = arrCompanies[i];
	  			sbMessage.append("<BR>Company Number : ").append(companyNumber);	// Company number.
	  			sbMessage.append("<BR><B>Company Name   : ").append(arrCompanies[i + 1]).append("</B>");	// Company name.
	  			sbMessage.append("<BR>");

	  			sbAttachment.append(companyNumber).append(',').append(reportId).append("\r\n");
	  		}
	  		sbMessage.append("<P><PRE>").append(sbAttachment).append("</PRE>");
		  	sbMessage.append("</font>");
  		}

		// Companies to remove.

		if(arrCompaniesToRemove!= null){
			sbAttachment = new StringBuffer();
			sbMessage.append("<font color=\'red'>");
			sbMessage.append("<HR><B>Companies to Remove</B><HR>");
  			for(int i=0;i<arrCompaniesToRemove.length;i+=2){
	  			String companyNumber = arrCompaniesToRemove[i];
	  			sbMessage.append("<BR>Company Number : ").append(companyNumber);	// Company number.
	  			sbMessage.append("<BR><B>Company Name   : ").append(arrCompaniesToRemove[i + 1]).append("</B>");	// Company name.
	  			sbMessage.append("<BR>");

	  			sbAttachment.append(companyNumber).append(',').append(reportId).append("\r\n");
	  		}
	  		sbMessage.append("<P><PRE>").append(sbAttachment).append("</PRE>");
		  	sbMessage.append("</font>");
  		}

		String mailTo  = resource.getProperty("mail.to");

		String subject = null;	// subject of the mail varies according to the type of user.
		String nextView = null;	// where to go from here,varies according to the type of user.

		// determine the type of user.
		Integer iObj = (Integer)session.getAttribute("userType");
		if(USER_TYPE_FREE_UPDATES.equals(iObj)){
			subject = resource.getProperty("mail.subject.freeupdates");
			nextView = "/mr_loginFreeUpdates.jsp";
		}else{
			subject = resource.getProperty("mail.subject.merlinreseacher");
			nextView = "/mr_login.jsp";
		}

		MailSender.sendMail(mailFrom,mailTo,subject,sbMessage.toString());
		request.setAttribute("message","Mail sent successfully");

		// clean the servletcontext data explicitly
		/*
		String username = (String)session.getAttribute("username");
		boolean status =  ((Set)getServletContext().getAttribute("setLoggedInUsers")).remove(username);
  		System.out.println("in sendmail removed " + username + " : " + status);
  		*/
		session.invalidate();

		dispatch(request,response,nextView,false);
	}

    /**
     *
     */
	protected void handleLoadTitles(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
		if(!titlesLoaded){
			new ReportRefresher(getServletContext(),0).loadTitles();
			titlesLoaded = true;
		}
	}

	/**
	 *
	 */
    protected void handleCreatePDF(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
		String searchString = request.getParameter("companyId");

		LookupDetailsBean ldBean  = LookupDetailsManager.selectLookupDetailsByPK(searchString) ;
		System.out.println(new Date().toLocaleString() + " ### MerlinServlet : begin generating PDF for company id " + searchString);
		if(ldBean != null){
			// if some record was found, retrieve the details of the record.
   			HashMap mapData = new HashMap();
			mapData.put("companyDetails",ldBean);
			String companyId = ldBean.getCompanyNumber();
   			DbResultSet dbRes = ShareholderDetailsManager.selectShareholderDetailsRecordsByCompanyNumber(companyId);

			mapData.put("shareholderDetails",dbRes);
			dbRes = DirectorDetailsManager.selectDirectorDetailsRecordsByCompanyNumber(companyId);
			mapData.put("directorDetails",dbRes);
			dbRes = ParentSubsidiaryDetailsManager.selectParentSubsidiaryDetailsRecordsByCompanyNumber(companyId);
			mapData.put("parentSubsidiaryDetails",dbRes);
			dbRes = FinancialDetailsManager.selectFinancialDetailsRecordsByCompanyNumber(companyId);
			mapData.put("financialDetails",dbRes);

			// create the PDF report,and stream it back to the client.
			System.out.println("#### MerlinServlet : getting PDF data");
			ByteArrayOutputStream pdfData = new PDFReportGenerator().generateReport(mapData);
			response.setContentType("application/pdf");
			response.setHeader("Content-disposition","inline; filename=" + searchString +".pdf");
			response.setContentLength(pdfData.size());
			OutputStream out = response.getOutputStream();
			pdfData.writeTo(out);
			pdfData.flush();
			out.flush();
			out.close();
			System.out.println(new Date().toLocaleString() + " ### MerlinServlet : finished sending PDF data");
		}else{
			response.setContentType("text/html");
			response.getWriter().println("<h4 align='center'>No report Found</h4>");
		}
	}


	protected void handleSearchReportsByDesc(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
		String searchString	= request.getParameter("txtSearch");

		//ApplicationResources resource = ApplicationResources.getInstance();

		if(searchString != null && ! searchString.trim().equals("")){
			/***
			Commented on Aug 2, 2007, new code to implement search tehnique similar to Google Landing page.
			//String sqlWhereClause = "REPORT_DESCRIPTION LIKE \'%" + searchString.toUpperCase() + "%\'";
			// new code to use the looksee query.
			String sqlWhereClause= " SATISFIES(NSD.IDX_REPORT_DESCRIPTION,'" + searchString.toUpperCase() + "') ";
			DbResultSet dbRes  = ReportTitlesManager.selectReportTitlesRecords(sqlWhereClause,"REPORT_TITLE");
			***/

			// new code (2 Aug 2007) implments search on lines of the Google Landing page.
			DbResultSet dbRes  = ReportTitlesManager.getGoogleLandingPageResult(searchString.toUpperCase());

			// put the result into the request
			request.setAttribute("reportDetails",dbRes);
		}
		String nextView = "/" + request.getParameter("pageName");
		//String nextView = "/mr_searchReports.jsp";
		dispatch(request,response,nextView,false);
	}

	protected void handleSaveNewEnquiry(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{

		String strFirstName			=	request.getParameter("txtFirstName");
		String strSurname			=   request.getParameter("txtSurname");
		String strCompanyName		=   request.getParameter("txtCompanyName");
		String strEMailAddress		=   request.getParameter("txtEMailAddress");
		String strTelephone			=   request.getParameter("txtTelephone");
		String strSelectedReports	=   request.getParameter("hidSelectedReports");

		ApplicationResources resource = ApplicationResources.getInstance();
		// break the selected reports list.

		//System.out.println("report is " + strSelectedReports);

		String separatorPattern = resource.getProperty("separatorPattern");
		String arrRawReports[] = strSelectedReports.split(separatorPattern);

		//System.out.println("report size " + arrRawReports.length);

		int arrReportIds[] = new int[arrRawReports.length/2];
		for(int i=0,j=0;i<arrReportIds.length;i++,j+=2){
			arrReportIds[i] = Integer.parseInt(arrRawReports[j]);
		}
		// Store the details in the database
		WebsiteEnquiriesManager.addWebsiteEnquiry(strFirstName,strSurname,strCompanyName,
									strEMailAddress,strTelephone,arrReportIds);

		// and send a mail to the administrator.
		StringBuffer sbMessage = new StringBuffer();

		sbMessage.append("First name: ").append(strFirstName).append("<BR>Surname: ").append(strSurname);
		sbMessage.append("<BR>Company Name: ").append(strCompanyName).append("<BR>E-Mail Address: ");
		sbMessage.append(strEMailAddress).append("<BR>Telephone: ").append(strTelephone).append("<BR>");
  		sbMessage.append("<BR>Date of enquiry : ").append(new java.util.Date().toLocaleString());

		for(int i=0;i< arrRawReports.length-1;i+=2){
	  		sbMessage.append("<BR>").append(arrRawReports[i]).append(" : ").append(arrRawReports[i+1]);
	  	}
		//System.out.println(sbMessage);


		String mailTo  = resource.getProperty("mail.to");
		String mailFrom = strEMailAddress;
		String subject = null;
		// Determine the subject of the mail based on the type of user.
		HttpSession session= request.getSession();
		Integer iObj = (Integer)session.getAttribute("userType");
		if(iObj != null && iObj.equals(USER_TYPE_FREE_UPDATES)){
			// A pre-existing customer has re-registered.
			subject = resource.getProperty("mail.subject.contactdetails.existingcustomer");
		}else{
			// A new client has provided contact details.
   			subject = resource.getProperty("mail.subject.contactdetails.newcustomer");
		}

		MailSender.sendMail(mailFrom,mailTo,subject,sbMessage.toString());

		//request.setAttribute("thankyou.message","Thank you for your enquiry. We will respond shortly.");
		String nextView = "mr_thankYouForEnquiry.jsp";
		// using redirect rather than forward so that the page gets logged in the server log.
		dispatch(request,response,nextView,true);
	}


    protected void handleSaveNewPaymentDetails(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{

		String strTitle				=	request.getParameter("txtTitle");
		String strFirstName			=   request.getParameter("txtFirstName");
		String strSurname			=   request.getParameter("txtSurname");
		String strPosition			=   request.getParameter("txtPosition");
		String strCompanyName		=   request.getParameter("txtCompanyName");
		String strAddress1			=   request.getParameter("txtAddress1");
		String strAddress2			=   request.getParameter("txtAddress2");
		String strTown				=   request.getParameter("txtTown");
		String strCounty			=   request.getParameter("txtCounty");
		String strPostcode			=   request.getParameter("txtPostcode");
		String strTelephone			=   request.getParameter("txtTelephone");
		String strEMailAddress		=   request.getParameter("txtEMailAddress");

		String strCardTitle			=   request.getParameter("txtCardTitle");
		String strCardForename		=   request.getParameter("txtCardForename");
		String strCardSurname		=   request.getParameter("txtCardSurname");
		String strCardPosition		=   request.getParameter("txtCardPosition");
		String strCardCompanyName	=   request.getParameter("txtCardCompanyName");
		String strCardAddress1		=   request.getParameter("txtCardAddress1");
		String strCardAddress2		=   request.getParameter("txtCardAddress2");
		String strCardTown			=   request.getParameter("txtCardTown");
		String strCardCounty		=   request.getParameter("txtCardCounty");
		String strCardPostcode		=   request.getParameter("txtCardPostcode");
		String strCardNumber		=   request.getParameter("txtCardNumber");
		String strCVV				=	request.getParameter("txtCVV");
        String strExpiryDate		=	request.getParameter("cmbMonth") + request.getParameter("cmbYear");
        String strFormatOptions 	=	request.getParameter("chkOptions");
		String strSelectedReports	=   request.getParameter("hidSelectedReports");
		String strTotalAmount		=   request.getParameter("edtTotal");
		String strCardType			=	request.getParameter("cmbCreditCardType");
		String strSameDetails		=	request.getParameter("radSameDetails");



        ApplicationResources resource = ApplicationResources.getInstance();

		// break the selected reports list.

		String separatorPattern = resource.getProperty("separatorPattern");
		String arrRawReports[] = strSelectedReports.split(separatorPattern);



		boolean cdDatabaseRequestedIndicator = ("Book(s) and database(s)".equals(strFormatOptions)) || ("Searchable Database(s) only".equals(strFormatOptions));
		boolean bookRequestedIndicator = ("Book(s) and database(s)".equals(strFormatOptions)) || ("Book(s) only".equals(strFormatOptions));
        boolean eBookRequestIndicator = "eBook".equals(strFormatOptions);

		WebsiteOrdersBean woBean = new WebsiteOrdersBean(0,strTitle,strFirstName,strSurname,strPosition,
											strCompanyName,strAddress1,strAddress2,strTown,strCounty,
											strPostcode,strTelephone,strEMailAddress,strCardNumber,strCVV,
											strExpiryDate,cdDatabaseRequestedIndicator,strCardTitle,
											strCardForename,strCardSurname,strCardPosition,strCardCompanyName,
											strCardAddress1,strCardAddress2,strCardTown,strCardCounty,
											strCardPostcode,bookRequestedIndicator,strTotalAmount,strCardType,
											strFormatOptions,"F".equals(strSameDetails),arrRawReports,false,eBookRequestIndicator);


		Map mapResponse = WebsiteEnquiriesManager.addWebsiteOrder(woBean);

		// Process the response from the ProtX site
		String returnCode = (String)mapResponse.get("Status");

		System.out.println("returned status code is  " + returnCode);
		System.out.println(request.getSession().getAttribute("autoFill"));

		if("OK".equals(returnCode)){
			// everything went fine. Do nothing.
		}else if("ERROR".equals(returnCode) || "MALFORMED".equals(returnCode)){
			// some fault has occured due to malformed request message or from the server-end.
			// Go to the error page.
			request.setAttribute("problem",mapResponse.get("StatusDetail"));
			dispatch(request,response,"/mr_problems.jsp",false);
			return;
		}else if("NOTAUTHED".equals(returnCode) || "REJECTED".equals(returnCode) || "INVALID".equals(returnCode)){
			// Some problem in the data entered by the client. Send back to the payment details
			// page for rectification.
			//request.setAttribute("problem",mapResponse.get("StatusDetail"));
			forceFillAutoFillDetails(request,(String)mapResponse.get("StatusDetail"));
			dispatch(request,response,"/mr_providePaymentDetails.jsp",false);
			return;
		}else{
			// Mismatch in return code. Go to the error page.
			request.setAttribute("problem",mapResponse.get("StatusDetail"));
			dispatch(request,response,"/mr_problems.jsp",false);
			return;
		}


		// send a mail to the administrator.
		StringBuffer sbMessage = new StringBuffer();

		sbMessage.append("Order Number: ").append(mapResponse.get("OrderId")).append("<br>");
		sbMessage.append("First name: ").append(strFirstName).append("<BR>Surname: ").append(strSurname);
		sbMessage.append("<BR>Company Name: ").append(strCompanyName).append("<BR>E-Mail Address: ").append(strEMailAddress).append("<BR>");
  		sbMessage.append("<BR>Date of enquiry : ").append(new java.util.Date().toLocaleString());

		for(int i=0;i< arrRawReports.length-1;i+=2){
	  		sbMessage.append("<BR>" + arrRawReports[i] + " : " + arrRawReports[i+1]);
	  	}
	  	sbMessage.append("<BR>Format(s) ordered: ").append(strFormatOptions);

		String mailTo  = resource.getProperty("mail.to");
		String mailFrom = strEMailAddress;
		String subject =  null;

		// Determine the subject of the mail based on the type of user.
		HttpSession session= request.getSession();
		Integer iObj = (Integer)session.getAttribute("userType");
		if(iObj != null && iObj.equals(USER_TYPE_FREE_UPDATES)){
			// A pre-existing customer has re-registered.
			subject = resource.getProperty("mail.subject.paymentdetails.existingcustomer");
		}else{
			// A new client has provided contact details.
   			subject = resource.getProperty("mail.subject.paymentdetails.newcustomer");
		}

		MailSender.sendMail(mailFrom,mailTo,subject,sbMessage.toString());

		//send an e-mail to the customer confirming the order
		sbMessage.append("<br>We will send the report(s) shortly.<br><br>Niel Dalrymple<br>Merlin Scott Associates Limited");
		sbMessage.insert(0, "Thank you for your recent order which has been received safely. Your order number is<br> ");

		mailFrom = resource.getProperty("mail.to");
		mailTo 	 = strEMailAddress;
		MailSender.sendMail(mailFrom,mailTo,subject,sbMessage.toString());

		// move to the "Thank You" page
		//request.setAttribute("thankyou.message","Thank you for your order. We will respond shortly.");
		String nextView = "http://" + ApplicationResources.getInstance().getProperty("iwBaseURL") + "/mr_thankYouForOrdering.jsp";;
		// using redirect rather than forward so that the page gets logged in the server log.
		dispatch(request,response,nextView,true);

		/*
		// dispatching is done from inside the code itself as it has to do some special processing.
		ApplicationResources resources = ApplicationResources.getInstance();
		String contextURL = resources.getProperty("application.url");
		String nextPage = resources.getProperty("secure.creditcarddetails.page");
		ServletContext context = getServletContext().getContext(contextURL);
		RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(nextPage);
		dispatcher.forward(request, response);
		*/
	}

	protected void handleSaveNewCustomerRegistration(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{

		String strFirstName			=	request.getParameter("txtFirstName");
		String strSurname			=   request.getParameter("txtSurname");
		String strCompanyName		=   request.getParameter("txtCompanyName");
		String strEMailAddress		=   request.getParameter("txtEMailAddress");
		String strPostcode			=   request.getParameter("txtPostcode");
		int iSelectedReport			=   Integer.parseInt(request.getParameter("lstReportTitles"));
		String strReportName		= 	request.getParameter("reportName");

		ApplicationResources resource = ApplicationResources.getInstance();

		// Store the details in the database

		MsalResearchersManager.addRegistrationDetails(iSelectedReport,strFirstName,strSurname,strCompanyName,strPostcode,strEMailAddress);

		// and send a mail to the administrator.
		StringBuffer sbMessage = new StringBuffer();
		sbMessage.append("First name : ").append(strFirstName).append("<BR>Surname : ").append(strSurname);
		sbMessage.append("<BR>Company Name : ").append(strCompanyName).append("<BR>Postcode : ").append(strPostcode);
		sbMessage.append("<BR>E-Mail Address : ").append(strEMailAddress).append("<BR>Report Title: ");
  		sbMessage.append("<BR>Date of enquiry : ").append(new java.util.Date().toLocaleString());
		sbMessage.append(strReportName).append("<BR><BR>");

		//System.out.println(sbMessage);


		String mailTo  = resource.getProperty("mail.to");
		String mailFrom = strEMailAddress;
		String subject = "New Customer Registration On Website";

		MailSender.sendMail(mailFrom,mailTo,subject,sbMessage.toString());

		String nextView = "/mr_thankYouForRegistering.jsp";
		dispatch(request,response,nextView,false);

	}

	/**
	 * Save a new Industry Watch Order.
	 */
	protected void handleSaveNewIWOrder(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
		//fill in the rest of the values in the iwRegBean
		HttpSession session = request.getSession();
		IWRegistrationBean iwRegBean = (IWRegistrationBean)session.getAttribute("iwRegBean");
		JspRuntimeLibrary.introspect(iwRegBean, request);

		Map mapResponse = WebsiteEnquiriesManager.addIWOrder(iwRegBean);

		// Process the response from the ProtX site
		String returnCode = (String)mapResponse.get("Status");

		System.out.println("returned status code is  " + returnCode);

		if("OK".equals(returnCode)){
			// everything went fine. Do nothing.
		}else if("ERROR".equals(returnCode) || "MALFORMED".equals(returnCode)){
			// some fault has occured due to malformed request message or from the server-end.
			// Go to the error page.
			request.setAttribute("problem",mapResponse.get("StatusDetail"));
			dispatch(request,response,"/mr_problems.jsp",false);
			return;
		}else if("NOTAUTHED".equals(returnCode) || "REJECTED".equals(returnCode) || "INVALID".equals(returnCode)){
			// Some problem in the data entered by the client. Send back to the payment details
			// page for rectification.
			//request.setAttribute("problem",mapResponse.get("StatusDetail"));
			iwRegBean.setErrorMessage("Authorisation declined by bank. - Check all the details you have entered below carefully.  If it is likely the credit limit has been exceeded please try another card or telephone 01369 840 643 for assistance.");
			dispatch(request,response,"/mr_creditCardDetails.jsp",false);
			return;
		}else if("3DAUTH".equals(returnCode)){
   			// 3d-secure rediraction required.
      		request.setAttribute("ACSURL", 	(String)mapResponse.get("ACSURL"));
      		request.setAttribute("MD", 		(String)mapResponse.get("MD"));
      		request.setAttribute("PAReq", 	(String)mapResponse.get("PAReq"));
      		dispatch(request,response,"/mr_redirectToBank.jsp",false);
      		return;
		}else{
			// Mismatch in return code. Go to the error page.
			request.setAttribute("problem",mapResponse.get("StatusDetail"));
			dispatch(request,response,"/mr_problems.jsp",false);
			return;
		}

		String nextView = "";
		ApplicationResources resource = ApplicationResources.getInstance();
		if(iwRegBean.isPdfDownloadPurchase()){
			IndustryWatchManager.generatePDFReportDownload((IWCustomerDetailsBean)session.getAttribute("IWUserDetails"),iwRegBean.getHidReportIds());
			session.removeAttribute("iwRegBean");
			nextView = "http://" + resource.getProperty("iwBaseURL") + "/iwReportDownloadMessage.jsp";
		}else{
			nextView = "http://" + resource.getProperty("iwBaseURL") + "/mr_thankYouForOrdering.jsp";
		}
		// using redirect rather than forward so that the page gets logged in the server log.
		dispatch(request,response,nextView,true);
	}

	/**
	 * A IW customer wants to do re-registration.
	 */
   	protected void handleIWReRegistration(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
	   	String emailAddress = request.getParameter("hidEmailAddress");
	   	IWRegistrationBean iwRegBean = WebsiteEnquiriesManager.getIWOrder(emailAddress);
     	request.getSession().setAttribute("iwRegBean",iwRegBean);
     	// depending on whether the user has subscribed to the IW reports or Merlin Reports,
     	// redirect the user.
     	if("A".equals(iwRegBean.getChkIndustryWatch()) || "B".equals(iwRegBean.getChkIndustryWatch()) || "C".equals(iwRegBean.getChkIndustryWatch())){
     		dispatch(request,response,"/mr_reportSelection.jsp?view=IndustryWatch",false);
     	}else{
     		dispatch(request,response,"/mr_reportSelection.jsp",false);
     	}
	}

	/**
	 * Handles the returned 3D Secure callback submission from the issuing bank after the
	 * user has interactered with the issuing bank.
	 */
   	protected void handle3DSecureCallback(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
   		String MDValue 		= request.getParameter("MD");
   		String PaResValue 	= request.getParameter("PaRes");

		IWRegistrationBean iwRegBean = (IWRegistrationBean)request.getSession().getAttribute("iwRegBean");
		Map mapResponse = WebsiteEnquiriesManager.handle3DCallback(iwRegBean,MDValue,PaResValue);

		// Process the response from the ProtX site
		String returnCode = (String)mapResponse.get("Status");

		System.out.println("returned status code is  " + returnCode);

		if("OK".equals(returnCode)){
			// everything went fine. Do nothing.
		}else if("ERROR".equals(returnCode) || "MALFORMED".equals(returnCode)){
			// some fault has occured due to malformed request message or from the server-end.
			// Go to the error page.
			request.setAttribute("problem",mapResponse.get("StatusDetail"));
			dispatch(request,response,"/mr_problems.jsp",false);
			return;
		}else if("NOTAUTHED".equals(returnCode) || "REJECTED".equals(returnCode) || "INVALID".equals(returnCode)){
			// Some problem in the data entered by the client. Send back to the payment details
			// page for rectification.
			//request.setAttribute("problem",mapResponse.get("StatusDetail"));
			iwRegBean.setErrorMessage("Authorisation declined by bank. - Check all the details you have entered below carefully.  If it is likely the credit limit has been exceeded please try another card or telephone 01369 840 643 for assistance.");
			dispatch(request,response,"/mr_creditCardDetails.jsp",false);
			return;
		}else{
			// Mismatch in return code. Go to the error page.
			request.setAttribute("problem",mapResponse.get("StatusDetail"));
			dispatch(request,response,"/mr_problems.jsp",false);
			return;
		}

		String nextView = "http://" + ApplicationResources.getInstance().getProperty("iwBaseURL") + "/mr_thankYouForOrdering.jsp";
		// using redirect rather than forward so that the page gets logged in the server log.
		dispatch(request,response,nextView,true);
  	}

	/**
	 * Function to check if a valid userid is already present in the database.
	 */
   	protected void handleCheckForLoginExistance(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
		String uid = request.getParameter("txtEmailAddress");

		String nextView = null;
		boolean redirect = false;

		uid = uid.toLowerCase().trim();

		CustomerDetailsBean bean = MsalResearchersManager.loginForFreeUpdates(uid);
		if(bean==null){
			// user not found. Send him to registration page.
			nextView = "mr_customerRegistration.jsp";
			redirect = true;
		}else{
			// check for the validity of the user's subscripttion.
   			Date subsEndDate = bean.getSubscriptionEndDate();

			long expiryDateMillis 	= subsEndDate.getTime();
			long currentDateMillis 	= System.currentTimeMillis();

			if(currentDateMillis < expiryDateMillis){
				//  subscription is still valid.
				request.setAttribute("username",uid);
				nextView = "/mr_subscriptionExists.jsp";
				redirect = false;
			}else{
				nextView = "mr_customerRegistration.jsp";
				redirect = true;
			}
		}
		dispatch(request,response,nextView,redirect);
	}

	/**
	 * Function to handle the interactions regarding the purchase of PDF report downloads.
	 */
	protected void handleBuyPdfCredits(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
	   	String emailAddress = request.getParameter("hidEmailAddress");
	   	IWRegistrationBean iwRegBean = WebsiteEnquiriesManager.getIWOrder(emailAddress);
		JspRuntimeLibrary.introspect(iwRegBean, request);
		iwRegBean.setChkMerlinReports("F");
		iwRegBean.setChkIndustryWatch("");
		iwRegBean.setPdfDownloadPurchase(true);
     	request.getSession().setAttribute("iwRegBean",iwRegBean);

        dispatch(request,response,ApplicationResources.getInstance().getProperty("secure.creditcarddetails.page"),true);
	}

	/**
	 * Function to generate the PDF report download mails.
	 */
	protected void handleGenerateReportDownload(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
		IndustryWatchManager.generatePDFReportDownload((IWCustomerDetailsBean)request.getSession().getAttribute("IWUserDetails"),request.getParameter("hidReportIds"));
		dispatch(request,response,"iwReportDownloadMessage.jsp",true);
	}

	/**
	 * Provides the PDF downloads of Merlin reports.
	 */
	protected void handlePdfReportDownload(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException,ParseException{
		long start = System.currentTimeMillis();
		String downloadId = request.getParameter("downloadId");
		//boolean bibService = Boolean.valueOf(request.getParameter("bibService"));
		int reportFormat = Integer.parseInt(request.getParameter("reportFormat"));
		
		System.out.println("report format " + reportFormat);
		PDFReportFileBean pdfData = IndustryWatchManager.getMerlinEbookReportByUUID(downloadId, reportFormat);

		sendReportDataForDownload(pdfData, reportFormat, response);
  		System.out.println(System.currentTimeMillis() - start);
	}

	protected void handleDownloadMailingList(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException,ParseException{
		int listingId = Integer.parseInt(request.getParameter("listingId"));

		EmailListingBean bean = MSALControlSystemManager.getEmailListingBeanByListingId(listingId);

		if(bean != null){
			response.setContentType("text/plain");
			//have to put the filename in double quotes otherwise the filename gets truncated to the first word of the file while downloading
			response.setHeader("Content-Disposition","attachment;filename=\"" + bean.getDescription() + " " + new SimpleDateFormat("dd/MM/yy").format(bean.getCreationDate()) + ".txt\"");
			response.setContentLength(bean.getFileData().length);
	  		response.getOutputStream().write(bean.getFileData());
	  		response.getOutputStream().close();
		}
	}

	protected void handlePdfReportDownloadFreeUpdates(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException,ParseException{
		long start = System.currentTimeMillis();
		int reportId = Integer.parseInt(request.getParameter("downloadId"));
		int reportFormat = Integer.parseInt(request.getParameter("reportFormat"));
		
		System.out.println("report format " + reportFormat);
		CustomerDetailsBean bean = (CustomerDetailsBean)request.getSession().getAttribute("userDetails");
		PDFReportFileBean pdfData = IndustryWatchManager.getPDFReportForFreeUpdatesByReportId(reportId,bean, reportFormat);
		
		sendReportDataForDownload(pdfData, reportFormat, response);
  		System.out.println("time taken : " + (System.currentTimeMillis() - start));
	}



	protected void handlePrinterLabelGeneration(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException,ParseException{
		response.setContentType("application/pdf");
		response.setHeader("Content-Disposition","attachment;filename=\"printer labels.pdf\"");
		JasperReportsGenerator.generatePrinterLabels(response.getOutputStream());
	}

	protected void handleMSALFreeReportDownload(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException,ParseException{
		long start = System.currentTimeMillis();
		int reportId = Integer.parseInt(request.getParameter("downloadId"), 16);
		int reportFormat = MerlinUtilities.REPORT_TYPE_PDF;
		
		PDFReportFileBean pdfData = IndustryWatchManager.getPDFReportForMSALFreeReportDownloadByRecordId(reportId);
		
		sendReportDataForDownload(pdfData, reportFormat, response);
  		System.out.println("time taken : " + (System.currentTimeMillis() - start));
	}
	
	/**
	 * Forwards/redirects the request to the requested resource.
	 */
	protected void dispatch(HttpServletRequest request,HttpServletResponse response,String page,boolean redirect)throws ServletException,IOException{
		if(redirect){
			System.out.println("redirecting to " + page);
			response.sendRedirect(page);
		}else{
			System.out.println("forwarding to " + page);
			RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(page);
			dispatcher.forward(request, response);
		}
	}

	protected void forceFillAutoFillDetails(HttpServletRequest request,String errorMessage)throws ServletException{
		HttpSession session = request.getSession();
		AutoFillDetails autoFill = (AutoFillDetails)session.getAttribute("autoFill");
		if(autoFill != null){
			// forcibly fill the bean contents.
			JspRuntimeLibrary.introspect(autoFill, request);
			autoFill.setErrorMessage(errorMessage);
			session.setAttribute("autoFill",autoFill);
		}
	}

	/**
	 * Function to check if someone with the same user id has logged in from some
	 * other computer already.
	 */
	private boolean isAnotherUserLoggedInFromAnotherIP(String uidAndIP, Iterator values){
		String uid = uidAndIP.substring(0,uidAndIP.indexOf(":"));
		System.out.println(uid + " --- " + uidAndIP);
		while(values.hasNext()){
			String uidAndIPEntry = (String)values.next();
			// if the uid part matches but the entire string doesn't (different IP address), return true.
			if(uidAndIPEntry.startsWith(uid) && ! uidAndIPEntry.equals(uidAndIP)){
				return true;
			}
		}

		return false;
	}

	/**
	 * Unzips the contents of the pdfData bean's file contents, and fills it back into the file contents.
	 * Unzip the file, change the bean's data, and set it for deletion later on.
	 * 
	 * @param pdfData
	 * @throws IOException
	 * @throws FileNotFoundException
	 */
	private void unZipDataContents(PDFReportFileBean pdfData)throws IOException, FileNotFoundException {
		String scratchPath = ApplicationResources.getInstance().getProperty("iwSummaryPDFStorageFolder");
		// save the data in a temp zip file.
		File zippedFile = File.createTempFile("rpt",".zip",new File(scratchPath));
		System.out.println("Saving zipped file here " + zippedFile);
		zippedFile.deleteOnExit();
		FileOutputStream fOut = new FileOutputStream(zippedFile);
		fOut.write(pdfData.getFileData());
		fOut.close();
		// unzip the file.
		ZipInputStream  zipIn = new ZipInputStream(new BufferedInputStream(new FileInputStream(zippedFile)));
		ZipEntry entry = zipIn.getNextEntry();
		if(entry != null){
			int count;
			byte data[] = new byte[1000];
			ByteArrayOutputStream pdfOut = new ByteArrayOutputStream();
			while ((count = zipIn.read(data,0,1000)) != -1){
				pdfOut.write(data,0,count);
			}
			pdfOut.flush();
			pdfOut.close();
			pdfData.setFileData(pdfOut.toByteArray());
		}
		zipIn.close();

		// delete the file.
		zippedFile.delete();
		System.out.println("cleaned up");
	}
	
	/**
	 * Streams the contents of the report to the servlet response stream.
	 * 
	 * @param pdfData
	 * @param reportFormat
	 * @param response
	 * @throws IOException
	 */
	private void sendReportDataForDownload(PDFReportFileBean pdfData,
			int reportFormat, HttpServletResponse response) throws IOException {
		if(pdfData != null && pdfData.getFileName() != null){
			String contentType = null;
			//have to put the filename in double quotes otherwise the filename gets truncated to the first word of the file while downloading
			String contentDisposition = null;   

			// type of report the user wants to download.
			switch(reportFormat){
			case MerlinUtilities.REPORT_TYPE_PDF :
				contentType = "application/pdf";
				contentDisposition = "attachment;filename=\"" + pdfData.getFileName() + "\"";
				break;
			case MerlinUtilities.REPORT_TYPE_XLS :
				contentType = "application/vnd.ms-excel";
				contentDisposition =  "attachment;filename=\"" + pdfData.getFileName().replaceAll(".pdf", " (Spreadsheet).xls") + "\"";
				break;
			case MerlinUtilities.REPORT_TYPE_RANKINGS :	
				contentType = "application/vnd.ms-excel";
				contentDisposition =  "attachment;filename=\"" + pdfData.getFileName().replaceAll(".pdf", " (Rankings).xls") + "\"";
				break;
			}			
			System.out.println("contentDisposition " + contentDisposition);

			response.setContentType(contentType);
			response.setHeader("Content-Disposition",contentDisposition);
			response.setContentLength(pdfData.getFileData().length);
	  		response.getOutputStream().write(pdfData.getFileData());
	  		response.getOutputStream().close();
		}
	}
	
	/**
	 * Thread to continuously refresh the report titles stored in the servletcontext.
	 */
	class ReportRefresher extends Thread{
		ServletContext context;
		int refreshInterval;
		public boolean isServerActive = true;

		/**
		 *
		 */
		ReportRefresher(ServletContext context,int refreshInterval){
			this.context = context;
			this.refreshInterval = refreshInterval;
		}

		/**
		 *
		 */
		public void run(){
			try{
				while(isServerActive){
					loadTitles();
					System.out.println("Going to sleep for " + (refreshInterval * 60 * 1000) + " milliseconds");
    				sleep(refreshInterval * 60 * 1000);	// converted to milliseconds
    			}
    		}catch(InterruptedException ie){
    			// Thread has been interrupted. Ignore the error and stop the thread.
    			System.out.println("ReportRefresher Thread interrupted");
			}catch(Exception e){
				e.printStackTrace();
			}
		}

		/**
		 *
		 */
		public void loadTitles(){
			// cache the report titles, as they will be used repeatedly.

			//Only those reports whose CUSTOMISED_INDICATOR is not TRUE are to be shown.
			String whereClause = "REPORT_TITLE <> 'AAA' and coalesce(CUSTOMISED_INDICATOR,false) <> true";
			String orderBy = "REPORT_TITLE";	// order by the report titles
	  		DbResultSet result = ReportTitlesManager.selectReportTitlesRecords(whereClause,orderBy);
			// format it into a select list to avoid repeated conversion.
			StringBuffer sBuf = new StringBuffer(2000);
			for(int i=0;i< result.getTotalRecords();i++){
				ReportTitlesBean bean = (ReportTitlesBean)result.get(i);
				sBuf.append("<option value='").append(bean.getReportTitlesId()).append("'>").append(bean.getReportTitle()).append("</option>");
			}
			context.setAttribute("reportTitles",sBuf);

			System.out.println("Updated report data on " + new Date().toLocaleString());
		}
	}
}